/**
 * DOM操作工具函数
 * @author Wu.Liang
 * @date 2025-01-30
 */

/**
 * 安全地获取元素的getBoundingClientRect
 */
export function safeGetBoundingClientRect(element: Element | string | null | undefined): DOMRect | null {
  try {
    if (!element) {
      console.warn('DOM工具: 元素为null或undefined')
      return null
    }

    let targetElement: Element | null = null

    // 如果是字符串，尝试通过选择器查找元素
    if (typeof element === 'string') {
      targetElement = document.querySelector(element)
    } else {
      targetElement = element
    }

    if (!targetElement) {
      console.warn('DOM工具: 无法找到目标元素')
      return null
    }

    // 检查元素是否在DOM中
    if (!document.contains(targetElement)) {
      console.warn('DOM工具: 元素不在DOM中')
      return null
    }

    // 检查元素是否可见
    const style = window.getComputedStyle(targetElement)
    if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
      console.warn('DOM工具: 元素不可见')
      return null
    }

    const rect = targetElement.getBoundingClientRect()
    
    // 检查元素是否有有效尺寸
    if (rect.width === 0 && rect.height === 0) {
      console.warn('DOM工具: 元素尺寸为0')
      return null
    }

    return rect
  } catch (error) {
    console.warn('DOM工具: getBoundingClientRect调用失败:', error)
    return null
  }
}

/**
 * 等待元素准备就绪
 */
export function waitForElement(selector: string, timeout: number = 5000): Promise<Element | null> {
  return new Promise((resolve) => {
    const startTime = Date.now()
    
    const checkElement = () => {
      const element = document.querySelector(selector)
      
      if (element) {
        // 检查元素是否完全渲染
        const rect = element.getBoundingClientRect()
        if (rect.width > 0 && rect.height > 0) {
          resolve(element)
          return
        }
      }
      
      // 检查超时
      if (Date.now() - startTime > timeout) {
        console.warn(`等待元素 ${selector} 超时`)
        resolve(null)
        return
      }
      
      // 继续等待
      requestAnimationFrame(checkElement)
    }
    
    checkElement()
  })
}

/**
 * 安全地滚动到元素
 */
export function safeScrollToElement(element: Element | string, options: ScrollIntoViewOptions = {}): void {
  try {
    let targetElement: Element | null = null

    if (typeof element === 'string') {
      targetElement = document.querySelector(element)
    } else {
      targetElement = element
    }

    if (!targetElement) {
      console.warn('DOM工具: 无法找到要滚动的元素')
      return
    }

    if (!document.contains(targetElement)) {
      console.warn('DOM工具: 元素不在DOM中，无法滚动')
      return
    }

    targetElement.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'nearest',
      ...options
    })
  } catch (error) {
    console.warn('DOM工具: 滚动到元素失败:', error)
  }
}

/**
 * 检查元素是否可见
 */
export function isElementVisible(element: Element | null): boolean {
  if (!element) return false

  try {
    if (!document.contains(element)) return false

    const style = window.getComputedStyle(element)
    return style.display !== 'none' && 
           style.visibility !== 'hidden' && 
           style.opacity !== '0'
  } catch (error) {
    console.warn('DOM工具: 检查元素可见性失败:', error)
    return false
  }
}

/**
 * 检查元素是否有有效尺寸
 */
export function hasElementSize(element: Element | null): boolean {
  if (!element) return false

  try {
    const rect = element.getBoundingClientRect()
    return rect.width > 0 && rect.height > 0
  } catch (error) {
    console.warn('DOM工具: 检查元素尺寸失败:', error)
    return false
  }
}

/**
 * 防抖函数
 */
export function debounce<T extends (...args: any[]) => any>(
  func: T,
  wait: number
): (...args: Parameters<T>) => void {
  let timeout: NodeJS.Timeout | null = null
  
  return (...args: Parameters<T>) => {
    if (timeout) {
      clearTimeout(timeout)
    }
    
    timeout = setTimeout(() => {
      func(...args)
    }, wait)
  }
}

/**
 * 节流函数
 */
export function throttle<T extends (...args: any[]) => any>(
  func: T,
  limit: number
): (...args: Parameters<T>) => void {
  let inThrottle: boolean = false
  
  return (...args: Parameters<T>) => {
    if (!inThrottle) {
      func(...args)
      inThrottle = true
      setTimeout(() => {
        inThrottle = false
      }, limit)
    }
  }
}

/**
 * 安全的DOM操作包装器
 */
export function safeDOMOperation<T>(operation: () => T, fallback?: T): T | undefined {
  try {
    return operation()
  } catch (error) {
    if (error instanceof Error && 
        (error.message.includes('getBoundingClientRect') || 
         error.message.includes('_a2.getBoundingClientRect'))) {
      console.warn('DOM操作失败，使用fallback值:', error.message)
      return fallback
    }
    throw error
  }
}

/**
 * 延迟执行DOM操作
 */
export function delayDOMOperation<T>(operation: () => T, delay: number = 100): Promise<T> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        const result = operation()
        resolve(result)
      } catch (error) {
        reject(error)
      }
    }, delay)
  })
}

/**
 * 重试DOM操作
 */
export async function retryDOMOperation<T>(
  operation: () => T, 
  maxRetries: number = 3, 
  delay: number = 100
): Promise<T> {
  let lastError: Error | null = null

  for (let i = 0; i < maxRetries; i++) {
    try {
      return operation()
    } catch (error) {
      lastError = error as Error
      
      if (lastError.message.includes('getBoundingClientRect') || 
          lastError.message.includes('_a2.getBoundingClientRect')) {
        console.warn(`DOM操作失败，第${i + 1}次重试...`)
        await new Promise(resolve => setTimeout(resolve, delay))
        continue
      }
      
      throw error
    }
  }

  throw lastError || new Error('DOM操作重试失败')
}

/**
 * 等待DOM更新完成
 */
export function waitForDOMUpdate(): Promise<void> {
  return new Promise((resolve) => {
    requestAnimationFrame(() => {
      requestAnimationFrame(() => resolve())
    })
  })
}

/**
 * 检查Element Plus组件是否准备就绪
 */
export function isElementPlusReady(component: any): boolean {
  try {
    if (!component) return false
    
    // 检查组件是否有必要的DOM元素
    const element = component.$el || component.el
    if (!element) return false
    
    // 检查元素是否可见且有尺寸
    return isElementVisible(element) && hasElementSize(element)
  } catch (error) {
    console.warn('检查Element Plus组件状态失败:', error)
    return false
  }
}

/**
 * 等待Element Plus组件准备就绪
 */
export function waitForElementPlusReady(component: any, timeout: number = 5000): Promise<boolean> {
  return new Promise((resolve) => {
    const startTime = Date.now()
    
    const checkComponent = () => {
      if (isElementPlusReady(component)) {
        resolve(true)
        return
      }
      
      if (Date.now() - startTime > timeout) {
        console.warn('等待Element Plus组件准备就绪超时')
        resolve(false)
        return
      }
      
      requestAnimationFrame(checkComponent)
    }
    
    checkComponent()
  })
} 